/*
 *  Copyright 2004 Blandware (http://www.blandware.com)
 *
 *  Licensed under the Apache License, Version 2.0 (the "License");
 *  you may not use this file except in compliance with the License.
 *  You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 *  Unless required by applicable law or agreed to in writing, software
 *  distributed under the License is distributed on an "AS IS" BASIS,
 *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 *  See the License for the specific language governing permissions and
 *  limitations under the License.
 */
package com.blandware.atleap.webapp.taglib.core.logic;

import com.blandware.atleap.webapp.util.core.GlobalProperties;
import com.blandware.atleap.webapp.util.core.WebappConstants;
import org.apache.struts.Globals;

import javax.servlet.ServletContext;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.jsp.JspException;
import javax.servlet.jsp.PageContext;
import javax.servlet.jsp.SkipPageException;
import javax.servlet.jsp.tagext.SimpleTagSupport;
import java.io.File;
import java.util.Locale;
import java.util.StringTokenizer;

/**
 * <p>Provides headers for browser caching</p>
 * <p>Note: use this class only at stand-alone JSP (like JS script page) in its
 * first lines (before any output is given to browser).</p>
 * <p>
 * Allowed attrubutes are:
 * <ul>
 * <li>
 * <b>cache</b> - may be <code>&quot;true&quot;</code> or
 * <code>&quot;false&quot;</code>, or may be omitted. If omitted, then this
 * tag will try to cache only if 'max age' global property is positive. If this
 * attribute is used, it controlls whether to try to cache (if
 * <code>&quot;true&quot;</code>) or not
 * </li>
 * </ul>
 * </p>
 * <p/>
 * <p><a href="BrowserCache.java.html"><i>View Source</i></a></p>
 *
 * @author Andrey Grebnev <a href="mailto:andrey.grebnev@blandware.com">&lt;andrey.grebnev@blandware.com&gt;</a>
 * @version $Revision: 1.1 $ $Date: 2005/10/20 07:18:50 $
 * @jsp.tag name="browserCache"
 * body-content="empty"
 */
public class BrowserCacheTag extends SimpleTagSupport {

	protected Boolean cache = null;


	/**
     * Returns whether to cache or not
     *
	 * @return whether to cache
	 * @jsp.attribute required="false"
	 * rtexprvalue="true"
	 * type="java.lang.Boolean"
	 * description="Should the page be cached or not"
	 */
	public Boolean getCache() {
		return cache;
	}

    /**
     * Sets whether to cache or not
     *
     * @param cache whether to cache
     */
	public void setCache(Boolean cache) {
		this.cache = cache;
	}

	/**
	 * Processes the tag
	 *
	 * @throws javax.servlet.jsp.JspException if an error occurred while processing this tag
	 * @see javax.servlet.jsp.tagext.Tag#doEndTag
	 */

	public void doTag() throws JspException {

		PageContext pageContext = (PageContext) getJspContext();

		HttpServletResponse response = (HttpServletResponse) pageContext.getResponse();
		HttpServletRequest request = (HttpServletRequest) pageContext.getRequest();
		ServletContext context = pageContext.getServletContext();

        int maxAge = ((Integer)GlobalProperties.getInstance(context).getInteger(WebappConstants.CACHE_RESOURCE_MAXAGE_PROPERTY, -1)).intValue();

        boolean cache = this.cache == null ? maxAge >= 0 : this.cache.booleanValue();    

		if ( !cache ) {
			response.setHeader("Cache-Control", "no-cache,no-store,max-age=0");
			response.setHeader("Pragma", "no-cache");
		} else {
			boolean isCache = false;

			long lastModified = -1;
			String uri = request.getRequestURI();
			String contextPath = request.getContextPath();
			if ( uri != null ) {
				if ( contextPath != null && !contextPath.equals("") && !contextPath.equals("/") ) {
					uri = uri.substring(contextPath.length());
				}
				String realPath = context.getRealPath(uri);
				if ( realPath != null ) {

					File file = new File(realPath);
					try {
						lastModified = file.lastModified();
					} catch ( SecurityException ex ) {
						//do nothing
					}

					//check for entity tag
					if ( request.getMethod().equals("GET") && lastModified != -1 && lastModified != 0 ) {
						isCache = true;


						response.setHeader("Cache-Control", "public,max-age=" + maxAge);
						response.setHeader("Pragma", "");

						//ETag generation
						String language = "en";
						Locale locale = (Locale) request.getSession(true).getAttribute(Globals.LOCALE_KEY);
						if ( locale != null ) {
							language = locale.getLanguage();
						}
						String username = request.getRemoteUser();
						StringBuffer eTagBuffer = new StringBuffer("W/\"").append(language).append("-").append(username).append("-").append(lastModified).append("\"");
						String eTag = eTagBuffer.toString();
                        response.setHeader("ETag", eTag);

						boolean conditionSatisfied = false;
						String headerValue = request.getHeader("If-None-Match");
						if ( headerValue != null ) {
							if ( !headerValue.equals("*") ) {
								StringTokenizer commaTokenizer =
								        new StringTokenizer(headerValue, ",");
								while ( !conditionSatisfied && commaTokenizer.hasMoreTokens() ) {
									String currentToken = commaTokenizer.nextToken();
									if ( currentToken.trim().equals(eTag) ) {
										conditionSatisfied = true;
									}
								}
							} else {
								conditionSatisfied = true;
							}
							if ( conditionSatisfied ) {
								response.setStatus(HttpServletResponse.SC_NOT_MODIFIED);
								throw new SkipPageException();
							}
						}
					}
				}
			}

			//check for setup headers
			if ( !isCache ) {
				response.setHeader("Cache-Control", "no-cache,no-store,max-age=0");
				response.setHeader("Pragma", "no-cache");
			}
		}
	}

}
